package usbipclientsrv

import (
	log "github.com/sirupsen/logrus"
	"go.uber.org/atomic"
	"net"
	"sync"
	"time"
	"usbipproxy/common"
	"usbipproxy/domain/service"
	"usbipproxy/pb"
)

type UsbipClientServerServiceImpl struct {
	listener      net.Listener
	msgNotifySvc  service.MsgNotifyService
	clients       map[string]*UsbipCliSession
	clientsMu     sync.RWMutex
	tcpPort       int
	busId         string
	vendorId      string
	notifyConnId  int64
	closed        atomic.Bool
	lastHeartBeat time.Time
	clientCmdSvc  service.UsbIpClientCmdService
	wg            sync.WaitGroup
}

func (t *UsbipClientServerServiceImpl) RecvHeartbeat(busId, sessId string) error {
	t.lastHeartBeat = time.Now()
	log.Infof("UsbipClientServerServiceImpl RecvHeartbeat")
	return nil
}

func (t *UsbipClientServerServiceImpl) GetNotifyConnId() int64 {
	if t == nil {
		return 0
	}

	return t.notifyConnId
}

func (t *UsbipClientServerServiceImpl) GetBusId() string {
	if t == nil {
		return ""
	}

	return t.busId
}

func (t *UsbipClientServerServiceImpl) RecvAttachData(sessId string, data []byte) error {
	t.clientsMu.RLock()
	defer t.clientsMu.RUnlock()

	t.lastHeartBeat = time.Now()

	for _, item := range t.clients {
		if (sessId != "" && item.sessId != sessId) || item.closed.Load() {
			continue
		}
		select {
		case item.outAttachData <- data:
		default:
			log.Infof("UsbipServerServiceImpl sessId:%v RecvMsg chan full ", sessId)
		}
	}

	return nil
}

func (t *UsbipClientServerServiceImpl) RemoveBySessionId(sessId string) error {
	t.clientsMu.Lock()
	for _, item := range t.clients {
		if item.sessId == sessId {
			item.Stop()
			log.Infof("UsbipClientServerServiceImpl RemoveBySessionId:%v", sessId)
		}
		delete(t.clients, item.sessId)
	}
	t.clientsMu.Unlock()
	return nil
}

func (t *UsbipClientServerServiceImpl) Stop() {
	if !t.closed.CompareAndSwap(false, true) {
		return
	}
	log.Infof("UsbipServerServiceImpl stop busId:%v venderId:%v port:%v", t.busId, t.vendorId, t.tcpPort)
	t.clientCmdSvc.DetachByBusId(t.busId, t.vendorId)
	if t.listener != nil {
		t.listener.Close()
	}

	t.clientsMu.Lock()
	for _, item := range t.clients {
		item.Stop()
	}
	t.clientsMu.Unlock()

	/*
		toServerMsg := &pb.ProxyMsg{
			MsgType: pb.MsgType_SERVER_DETACH,
			Param: &pb.ProxyMsg_ServerDetachParam{ServerDetachParam: &pb.ServerDetachParam{
				BusId: t.busId,
			}},
		}
		t.msgNotifySvc.SendMsg(toServerMsg)
	*/
	//t.RecvMsg("", nil)
	//log.Infof("UsbipClientServerServiceImpl wait")
	//t.wg.Wait()
	//log.Infof("UsbipClientServerServiceImpl wait over")
}

func (t *UsbipClientServerServiceImpl) GetClientCount() int {
	cnt := 0
	t.clientsMu.RLock()
	cnt = len(t.clients)
	t.clientsMu.RUnlock()
	return cnt
}

func (t *UsbipClientServerServiceImpl) Start() (int, error) {
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		log.Infof("UsbipServerServiceImpl Listen error:%v", err)
		return 0, err
	}
	//defer listener.Close()
	t.listener = listener
	listenerStarted := make(chan struct{}, 1)

	t.wg.Add(2)
	go func() {
		defer t.wg.Done()
		listenerStarted <- struct{}{}
		t.listen()
		log.Infof("UsbipClientServerServiceImpl listen over 3")
	}()
	go func() {
		defer t.wg.Done()
		t.check()
		log.Infof("UsbipClientServerServiceImpl check over 2")
	}()

	<-listenerStarted

	addr := listener.Addr().(*net.TCPAddr)
	t.tcpPort = addr.Port
	log.Infof("Server started on port %d", addr.Port)
	return addr.Port, nil
}

func (t *UsbipClientServerServiceImpl) check() {
	//心跳 30秒一次
	tick := time.NewTicker(time.Second)
	defer tick.Stop()

	//n := 0
	cntTimes := 0
	n := 0
	for !t.closed.Load() {
		select {
		case <-tick.C:
			//log.Infof("====111110")
			now := time.Now()
			if now.After(t.lastHeartBeat.Add(time.Second * 30 * 5 / 2)) {
				log.Infof("UsbipServerServiceImpl heartbeat timeout t.lastHeartBeat:%v now:%v todo",
					t.lastHeartBeat, now)
				//t.lastHeartBeat = time.Now()
				t.Stop()
				return
			}
			if n%30 == 0 {
				//log.Infof("====111111")
				t.clientsMu.RLock()
				//log.Infof("====111112")
				for _, item := range t.clients {
					t.msgNotifySvc.SendMsg(&pb.ProxyMsg{
						MsgType: pb.MsgType_HEARTBEAT,
						Base: &pb.BaseParam{
							ToId: t.notifyConnId,
						},
						Param: &pb.ProxyMsg_HeartbeatParam{HeartbeatParam: &pb.HeartbeatParam{
							SessId: item.sessId,
							BusId:  t.busId,
						}},
					})
				}
				//log.Infof("====111113")
				t.clientsMu.RUnlock()
			}
			n++

			//连续3秒内没有活动的链接，则关掉
			cnt := t.GetClientCount()
			if cnt <= 0 {
				cntTimes++
				if cntTimes >= 3 {
					t.Stop()
					return
				}
			} else {
				cntTimes = 0
			}
		}
	}
	log.Infof("UsbipClientServerServiceImpl check over 1")
}

func (t *UsbipClientServerServiceImpl) listen() {
	for {
		conn, err := t.listener.Accept()
		if err != nil {
			log.Println("Accept error:", err)
			break
		}

		if tcpConn, ok := conn.(*net.TCPConn); ok {
			//tcpConn.SetNoDelay(true)
			tcpConn.SetReadBuffer(1024 * 1024)
			tcpConn.SetWriteBuffer(1024 * 1024)
		}

		clientID := conn.RemoteAddr().String()
		log.Infof("UsbipServerServiceImpl Client connected:%v", clientID)

		// 添加客户端到列表
		sessId := common.GetPureUuid()
		cli := t.addClient(clientID, sessId, t.notifyConnId, conn)

		// 处理客户端连接
		t.wg.Add(1)
		go func() {
			defer t.wg.Done()
			cli.handleConnection()
			t.removeClient(clientID)
			log.Infof("UsbipClientServerServiceImpl client over:%v", clientID)
		}()
	}
}

func NewUsbipClientServerServiceImpl(busId, vendorId string, notifyConnId int64,
	msgNotifySvc service.MsgNotifyService, clientCmdSvc service.UsbIpClientCmdService) UsbipClientServerService {
	return &UsbipClientServerServiceImpl{
		msgNotifySvc:  msgNotifySvc,
		clients:       make(map[string]*UsbipCliSession),
		busId:         busId,
		vendorId:      vendorId,
		notifyConnId:  notifyConnId, //通过哪一个tcp session 发出去
		lastHeartBeat: time.Now(),
		clientCmdSvc:  clientCmdSvc,
	}
}

func (t *UsbipClientServerServiceImpl) addClient(cliId, sessId string, notifyConnId int64, conn net.Conn) *UsbipCliSession {
	cli := NewUsbipCliSession(cliId, t.busId, t.vendorId, sessId, notifyConnId, conn, t.msgNotifySvc)

	t.clientsMu.Lock()
	defer t.clientsMu.Unlock()
	t.clients[cliId] = cli

	return cli
}

func (t *UsbipClientServerServiceImpl) removeClient(cliId string) {
	t.clientsMu.Lock()
	if cli, ok := t.clients[cliId]; ok {
		cli.Stop()
		delete(t.clients, cliId)
		log.Infof("UsbipServerServiceImpl removeClient %s", cliId)
	}
	t.clientsMu.Unlock()
}

func (t *UsbipClientServerServiceImpl) getClient(cliId string) (*UsbipCliSession, bool) {
	t.clientsMu.RLock()
	defer t.clientsMu.RUnlock()
	cli, ok := t.clients[cliId]
	return cli, ok
}
